﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Configuration;
using UL360Data;
using System.Reflection;
using UL360SurveyService.Utils;
using UL360SurveyService.Models;
using UL360SurveyCommon;

namespace UL360SurveyService
{
    public partial class SurveyService : ServiceBase
    {
        //New executionTime for checking if service should send mail
        private Timer ExecutionTimer { get; set; }

        //Timer to use for reloading mailing interval settings from db
        private Timer ReloadIntervalSettingsTimer { get; set; }
        
        //Contains all settings for service
        public Settings ServiceSettings { get; set; }

        public SurveyService()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Method firing when service is starting, sets startup parameters and checks if there are courses that have'nt had any mails sent
        /// </summary>
        /// <param name="args"></param>
        /// 
        protected override void OnStart(string[] args)
        {
            try
            {
                ServiceSettings = new Settings();
                
                //Create new executionTimer and set interval from app.settings
                ExecutionTimer = new Timer(ServiceSettings.ExecutionTimeSecondInterval * 1000);
                ExecutionTimer.Elapsed += ExecutionTimer_Elapsed;

                //Check if there are mails to be sent when service is starting
                MailSendingUtil.CheckToSendSurveyMail(ServiceSettings);
                MailSendingUtil.CheckToSendSurveyReminderMail(ServiceSettings);
                MailSendingUtil.CheckToSendExtSurveyMail(ServiceSettings);
                MailSendingUtil.CheckToSendExtSurveyReminderMail(ServiceSettings);

                ExecutionTimer.Start();

                //Create new time for reloading mailing interval settings, get interval from app.settings
                ReloadIntervalSettingsTimer = new Timer(ServiceSettings.TimeBetweenIntervalSettingsLoadingFromDb * 1000);
                ReloadIntervalSettingsTimer.Elapsed += ReloadIntervalSettingsTimer_Elapsed;
                ReloadIntervalSettingsTimer.Start();

                LoggerCommon.LogNewEntry(
                    new LoggerCommon.LogNewEntryDelegate(Logger.LogNewEntry), 
                    MethodBase.GetCurrentMethod().Name, "Service started\n\n" +
                    ServiceSettings.ToString(), 
                    (int)SurveyLoggingLevel.Information, true, ServiceSettings.EventlogSource);
            }
            catch (Exception exc)
            {
                //Log entry to windows eventlog if failed
                LoggerCommon.LogNewEventlogEntry(MethodBase.GetCurrentMethod().Name, exc.ToString(), (int)SurveyLoggingLevel.Error, 
                     this.ServiceName);
            }
        }

        void ReloadIntervalSettingsTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            ServiceSettings.LoadIntervalsFromDb();
        }

        protected override void OnStop()
        {
            try
            {
                //Stop timers
                ExecutionTimer.Stop();
                ExecutionTimer.Dispose();
                ReloadIntervalSettingsTimer.Stop();
                ReloadIntervalSettingsTimer.Dispose();
                
                //Log that service is stopping
                LoggerCommon.LogNewEntry(
                    new LoggerCommon.LogNewEntryDelegate(Logger.LogNewEntry), 
                    MethodBase.GetCurrentMethod().Name, "Service is shutting down",
                    (int)SurveyLoggingLevel.Information, true, ServiceSettings.EventlogSource);
            }
            catch (Exception exc)
            {
                Debug.WriteLine("Could not log that service is shutting down, exception: " + exc.ToString());
            }
        }

        /// <summary>
        /// Method that executes when executiontimer elapses
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ExecutionTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            try
            {
                //Stop executiontimer temporarily while mailing
                ExecutionTimer.Stop();

                /* Always run if runAtSpecificedTime is false, if runAtSpecifiedTime is set to true, only run when
                 * TimeToRun is the current time or TimeToRun has occured after lastExecutionTimerRun and before this 
                 * executionTimerRun */
                if (!ServiceSettings.RunAtSpecificTime || (
                        ServiceSettings.RunAtSpecificTime && (
                            ServiceSettings.TimeToRun.TimeOfDay == DateTime.Now.TimeOfDay || (
                                    ServiceSettings.TimeToRun.TimeOfDay > ServiceSettings.LastExecutionTimerRun.TimeOfDay &&
                                    ServiceSettings.TimeToRun.TimeOfDay < DateTime.Now.TimeOfDay
                                )
                            )
                        )
                    )
                {
                    //Check if survey mail should be sent
                    MailSendingUtil.CheckToSendSurveyMail(ServiceSettings);
                    MailSendingUtil.CheckToSendSurveyReminderMail(ServiceSettings);
                    MailSendingUtil.CheckToSendExtSurveyMail(ServiceSettings);
                    MailSendingUtil.CheckToSendExtSurveyReminderMail(ServiceSettings);
                }

                //Set last executionTimerRun to now
                ServiceSettings.LastExecutionTimerRun = DateTime.Now;

                //Start executiontimer again
                ExecutionTimer.Start();
            }
            catch (Exception exc)
            {
                //Log entry to windows eventlog if failed
                LoggerCommon.LogNewEventlogEntry(MethodBase.GetCurrentMethod().Name, exc.ToString(), 
                    (int)SurveyLoggingLevel.Error, ServiceSettings.EventlogSource);

                //If error occured before timer could be started again, try starting it now
                try
                {
                    //If not running already
                    if (!ExecutionTimer.Enabled)
                    {
                        ExecutionTimer.Start();
                    }
                }
                catch (Exception exc2)
                {
                    //Log that timer could not be restarted
                    LoggerCommon.LogNewEventlogEntry(MethodBase.GetCurrentMethod().Name, 
                        "Execution timer could not be restarted, exception: " + exc2.ToString(),
                        (int)SurveyLoggingLevel.Error, 
                    ServiceSettings.EventlogSource);
                }
            }
        }
    }
}
